﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using TVRageDAL;
using FilesTubeDAL;
using ShowDisplayElementControl;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Diagnostics;

namespace RED
{
    public partial class MainForm : Form
    {
        ShowDisplayElement[] _sdeArr;
        bool _showtooltip;
        readonly BackgroundWorker _bw;

        public MainForm()
        {
            InitializeComponent();
            showList.Comparer = new ItemComparerByDate();
            _bw = new BackgroundWorker();
            _bw.DoWork += bw_DoWork;
            _bw.RunWorkerCompleted += bw_RunWorkerCompleted;
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            LoadList();

            if (showList.Items.Count > 0)
            {
                showList.Items.Sort(showList.Comparer);
                showList.SelectControl(showList.Items[0]);
                showList.ShowTopItem();

                foreach (var item in showList.Items)
                {
                    item.MouseDoubleClick += item_DoubleClick;
                }

                _bw.RunWorkerAsync();
            }

            timer1.Interval = 1000 * 60 * 60 * 24;
        }

        void item_DoubleClick(object sender, EventArgs e)
        {
            var item = (ShowDisplayElement)showList.CurrentSelected;
            var rsdal = new RSDAL();
            var s = int.Parse(item.Season);
            var ep = int.Parse(item.Episode);
            var ss = IntToString(s);
            var ee = IntToString(ep);
            var uri = rsdal.SearchUrl + item.SearchName + " s" + ss + "e" + ee;

            if (item.IsHd)
                uri = uri + " 720p";

            Process.Start(Uri.EscapeUriString(uri));
        }

        void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            showList.BeginUpdate();

            for (var i = 0; i < _sdeArr.Length; i++)
            {
                showList.Items[i] = _sdeArr[i];
                showList.Items[i].Update();
            }

            showList.EndUpdate();

            if (!Visible && _showtooltip)
                notifyIcon1.ShowBalloonTip(5000, "Found new episodes!", "RED has found new episodes for you.", ToolTipIcon.Info);
        }

        void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            _sdeArr = new ShowDisplayElement[showList.Items.Count];

            if (e.Argument != null)
            {
                var f = (object[])e.Argument;
                CheckEpisodes((bool)f[0]);
            }
            else
            {
                CheckEpisodes();
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveList();
            Application.Exit();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var aboutForm = new AboutBox1();
            aboutForm.ShowDialog();
        }

        private void addShowButton_Click(object sender, EventArgs e)
        {
            var addForm = new AddShowForm();
            var dlg = addForm.ShowDialog();
            var dt = new DateTime();
            if (dlg != DialogResult.OK) return;

            if (showList.Items.FindIndex(control => ((ShowDisplayElement)control).ShowName == addForm.SelectedShow.Name) == -1)
            {
                var airdate = addForm.SelectedEpisode.AirDate == null || !DateTime.TryParse(addForm.SelectedEpisode.AirDate, out dt) ? "TBA" : dt.ToShortDateString();
                var sde = new ShowDisplayElement(addForm.SelectedShow.Name, addForm.SelectedShow.SearchName,
                                                 IntToString(int.Parse(addForm.SelectedEpisode.Season)),
                                                 IntToString(int.Parse(addForm.SelectedEpisode.Episode)),
                                                 addForm.SelectedEpisode.IsHd, airdate,
                                                 Color.Transparent, false)
                              {SelectedColor = Color.Gainsboro};

                showList.BeginUpdate();
                showList.Add(sde);
                var curr = showList.Items.Find(control => ((ShowDisplayElement) control).ShowName == sde.ShowName);
                curr.MouseDoubleClick += item_DoubleClick;
                showList.EndUpdate();

                SaveList();
                CheckEpisode((ShowDisplayElement)curr, true);
                RefreshEpisodeInformation((ShowDisplayElement)curr);
                showList.Items.Sort(showList.Comparer);
                showList.Rebuild();
            }
            else
            {
                MessageBox.Show(@"You already have " + addForm.SelectedShow.Name + @" in your list.");
            }
        }

        private void removeShow_Click(object sender, EventArgs e)
        {
            showList.BeginUpdate();
            showList.Remove(showList.CurrentSelected);
            showList.EndUpdate();
            SaveList();
        }

        private void editShow_Click(object sender, EventArgs e)
        {
            var editForm = new EditForm(((ShowDisplayElement)showList.CurrentSelected).ShowName, ((ShowDisplayElement)showList.CurrentSelected).AirDate, ((ShowDisplayElement)showList.CurrentSelected).Season, ((ShowDisplayElement)showList.CurrentSelected).Episode, ((ShowDisplayElement)showList.CurrentSelected).IsHd, ((ShowDisplayElement)showList.CurrentSelected).SearchName, ((ShowDisplayElement)showList.CurrentSelected).FutureEpisode);
            var dlg = editForm.ShowDialog();
            if (dlg != DialogResult.OK) return;
            
            showList.BeginUpdate();
            var currItem = (ShowDisplayElement)showList.CurrentSelected;
            currItem.Season = IntToString(int.Parse(editForm.Season));
            currItem.Episode = IntToString(int.Parse(editForm.Episode));
            currItem.IsHd = editForm.IsHd;
            currItem.SearchName = editForm.SearchParam;
            currItem.FutureEpisode = editForm.FutureEpisode;
            showList.EndUpdate();
            currItem.UpdateSeasonEpisodeLabel();
            CheckEpisode(currItem, true);
            RefreshEpisodeInformation(currItem);
            showList.Items.Sort(showList.Comparer);
            showList.Rebuild();
            SaveList();
        }

        private void checkEpisodes_Click(object sender, EventArgs e)
        {
            _bw.RunWorkerAsync(new object[1] { true });
        }

        private void showList_OnControlSelected(Control C)
        {
            if (C != null)
                C.BackColor = Color.Gainsboro;
        }

        private void showList_OnControlDeselected(Control C)
        {
            if (C != null)
                C.BackColor = showList.BackColor;
        }

        private void SaveList()
        {
            var showArr = new ShowDisplayElement[showList.Items.Count];

            for (var i = 0; i < showList.Items.Count; i++)
            {
                showArr[i] = (ShowDisplayElement)showList.Items[i];
            }

            var stream = File.Open(Environment.CurrentDirectory + @"\save.xml", FileMode.Create);
            var bf = new BinaryFormatter();
            bf.Serialize(stream, showArr);
            stream.Flush();
            stream.Close();
        }

        private void LoadList()
        {
            if (!File.Exists(Environment.CurrentDirectory + @"\save.xml")) return;
            var stream = File.Open(Environment.CurrentDirectory + @"\save.xml", FileMode.Open);
            var bf = new BinaryFormatter();
            var showArr = (ShowDisplayElement[])bf.Deserialize(stream);
            stream.Close();
            showList.Clear();

            foreach (var item in showArr)
            {
                if (item != null)
                    showList.Add(item);
            }

            showList.Update();
        }

        private static void RefreshEpisodeInformation(ShowDisplayElement item)
        {
            var tvdal = new TVDAL();
            if (item == null) return;
            var ep = tvdal.GetEpisodeInfo(item.ShowName, item.Season, item.Episode);
            var dt = new DateTime();
            var airdate = ep == null || !DateTime.TryParse(ep.AirDate, out dt) ? "TBA" : dt.ToShortDateString();

            if (item.InvokeRequired)
                item.Invoke(new Action<ShowDisplayElement, string>(UpdateAirDate), new object[] { item, airdate });
            else
                UpdateAirDate(item, airdate);
        }

        private static void UpdateAirDate(ShowDisplayElement item, string airDate)
        {
            item.AirDate = airDate;
        }

        private static bool CheckEpisode(ShowDisplayElement item, bool force = false)
        {
            var rsdal = new RSDAL();
            string search;
            DateTime odt;
            DateTime.TryParse(item.AirDate, out odt);
            var s = int.Parse(item.Season);
            var ep = int.Parse(item.Episode);
            var found = false;
            item.RsResults = null;
            var ss = IntToString(s);
            var ee = IntToString(ep);

            if (item.IsHd)
                search = item.SearchName + " s" + ss + "e" + ee + " 720p";
            else
                search = item.SearchName + " s" + ss + "e" + ee;

            if (odt <= DateTime.Today)
                item.RsResults = rsdal.GetSearchResults(search);
            else
                if (force)
                    item.RsResults = rsdal.GetSearchResults(search);

            if (item.RsResults != null)
                if (item.RsResults.Length > 3)
                {
                    item.Icon = Color.Green;
                    found = true;
                }
                else if (item.RsResults.Length < 3 && item.RsResults.Length >= 1)
                {
                    item.Icon = Color.Yellow;
                    found = true;
                }
                else
                {
                    item.Icon = Color.Red;
                }
            else
                item.Icon = Color.Red;

            return found;
        }

        private void CheckEpisodes(bool force = false)
        {
            _showtooltip = false;

            for (var i = 0; i < showList.Items.Count; i++)
            {
                _sdeArr[i] = (ShowDisplayElement)showList.Items[i];
                RefreshEpisodeInformation(_sdeArr[i]);
                _showtooltip = CheckEpisode(_sdeArr[i], force);
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            _bw.RunWorkerAsync();
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            //if (Visible)
            //    e.Cancel = true;

            //Visible = false;
            //notifyIcon1.ShowBalloonTip(5000, "RED is still running!", "To close RED completely, right click the icon and choose Exit", ToolTipIcon.Info);

            SaveList();
        }

        private void notifyIcon1_DoubleClick(object sender, EventArgs e)
        {
            Visible = true;
        }

        private void exitToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            SaveList();
            Application.Exit();
        }

        private void nextEpisodeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var cep = (ShowDisplayElement)showList.CurrentSelected;
            var tvdal = new TVDAL();
            var showInfo = tvdal.GetShowInfo(cep.ShowName, true, true);

            if (showInfo == null) return;
            // Determine how many episodes there is in a season
            var sec = showInfo.Episodes.Count(ep => ep != null && int.Parse(cep.Season) == int.Parse(ep.Season));
            // Determine how many seasons
            var sc = int.Parse(showInfo.Episodes.Last().Season);

            if (int.Parse(cep.Episode) + 1 <= sec)
            {
                // Within same season
                cep.Episode = IntToString(int.Parse(cep.Episode) + 1);
            }
            else
            {
                if (int.Parse(cep.Season) + 1 <= sc)
                {
                    // Next season
                    cep.Season = IntToString(int.Parse(cep.Season) + 1);
                    cep.Episode = "01"; 
                }
            }

            foreach (var ep in showInfo.Episodes.Where(ep => int.Parse(ep.Season) == int.Parse(cep.Season) && int.Parse(ep.Episode) == int.Parse(cep.Episode)))
            {
                cep.AirDate = ep.AirDate;
            }

            CheckEpisode(cep);
            cep.UpdateSeasonEpisodeLabel();
            RefreshEpisodeInformation(cep);
            showList.Items.Sort(showList.Comparer);
            showList.Rebuild();
            SaveList();
        }

        private void previosEpisodeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var cep = (ShowDisplayElement)showList.CurrentSelected;
            var tvdal = new TVDAL();
            var nep = int.Parse(cep.Episode);
            var ns = int.Parse(cep.Season);
            var showInfo = tvdal.GetShowInfo(cep.ShowName, true, true);

            if (nep - 1 >= 1)
            {
                // Within same season
                cep.Episode = IntToString(nep - 1);
            }
            else
            {
                if (ns > 1)
                {
                    // Previous season
                    cep.Season = IntToString(ns - 1);

                    // Determine how many episodes there is in a season
                    var sec = showInfo.Episodes.Count(ep => ep != null && int.Parse(cep.Season) == int.Parse(ep.Season));

                    cep.Episode = IntToString(sec);
                }
            }

            foreach (var ep in showInfo.Episodes.Where(ep => ep != null && int.Parse(cep.Season) == int.Parse(ep.Season) && int.Parse(cep.Episode) == int.Parse(ep.Episode)))
            {
                cep.AirDate = ep.AirDate;
            }

            CheckEpisode(cep);
            cep.UpdateSeasonEpisodeLabel();
            RefreshEpisodeInformation(cep);
            showList.Items.Sort(showList.Comparer);
            showList.Rebuild();
            SaveList();
        }

        private void removeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            removeShow_Click(sender, e);
        }

        private void editToolStripMenuItem_Click(object sender, EventArgs e)
        {
            editShow_Click(sender, e);
        }

        private static string IntToString(int i)
        {
            if (i < 10)
                return "0" + i;
            
            return i.ToString();
        }
    }
}
